<template>
  <el-popover
    ref="sortingConfigPaneRef"
    :virtual-ref="virtualRef"
    :visible="sortingConfigPaneVisible"
    :show-arrow="false"
    width="480px"
  >
    <div
      v-click-popover-outside:field-picker.exclude="onClickPopoverOutside"
      style="--el-fill-color-light: #eaebec"
    >
      <div class="flex justify-between items-center mb-4">
        <span class="text-xl text-gray-700 font-semibold">排序</span>
        <div
          class="flex justify-center items-center p-2 hover:bg-[#e3e5e5] rounded"
          @click="toggleSortingConfigPaneVisible(false)"
        >
          <i class="i-lucide-x" />
        </div>
      </div>
      <el-scrollbar :max-height="420" view-class="pr-4">
        <draggable
          v-model="sortingConfig"
          item-key="field"
          handle=".i-lucide-grip-vertical"
          @change="emit('update:sortBy')"
        >
          <template #item="{ element: config }: {element: SortingConfig}">
            <div class="flex items-center gap-x-2 py-2 px-4">
              <div class="shrink-0">
                <i
                  v-show="sortingConfig.length > 1"
                  class="i-lucide-grip-vertical cursor-move text-[18px]"
                />
              </div>
              <div class="flex-1">
                <el-select
                  v-model="config.refCol"
                  value-key="field"
                  @visible-change="onSelectVisibleChange"
                  @change="emit('update:sortBy')"
                >
                  <el-option
                    v-for="col in selectableColumns"
                    :key="`col-${col.field}`"
                    :value="col"
                    :label="col.title"
                  >
                    <div class="flex gap-x-2 items-center">
                      <i :class="[typeIcon[col.type], 'text-[16px] mr-1']" />
                      {{ col.title }}
                    </div>
                  </el-option>
                  <template #label>
                    <div class="flex gap-x-2 items-center">
                      <i
                        :class="[
													typeIcon[config.refCol.type],
													'text-[16px] mr-1'
												]"
                      />
                      {{ config.refCol.title }}
                    </div>
                  </template>
                </el-select>
              </div>
              <div class="shrink-0">
                <el-radio-group
                  v-model="config.sort"
                  @change="emit('update:sortBy')"
                >
                  <el-radio-button value="asc">
                    <component :is="SortingDescription(config, 'asc')" />
                  </el-radio-button>
                  <el-radio-button value="desc">
                    <component :is="SortingDescription(config, 'desc')" />
                  </el-radio-button>
                </el-radio-group>
              </div>
              <div
                class="flex justify-center items-center p-3 hover:bg-[#e3e5e5] rounded shrink-0"
                @click.stop="onRemoveSortingConfig(config)"
              >
                <i class="i-lucide-circle-minus" />
              </div>
            </div>
          </template>
        </draggable>
      </el-scrollbar>
      <div
        class="mt-2 flex justify-between pr-4"
        style="--el-fill-color: #e6e7e8"
      >
        <el-button
          v-click-outside="onClickOutside"
          text
          bg
          @click="onPickSortingField($event)"
        >
          <i class="i-lucide-plus text-[18px] mr-2" /> 添加排序条件
        </el-button>
      </div>
    </div>
  </el-popover>
</template>
<script setup lang="ts">
import { typeIcon, SortingDescription, toggle, tryit } from '../lib'
import type { ColumnConfig, SortingConfig } from '../types'
import { ElOption, ElSelect, ClickOutside as vClickOutside } from 'element-plus'
import draggable from 'vuedraggable'
import { clickPopoverOutside as vClickPopoverOutside } from '../directives'
import { useToggle } from '@vueuse/core'
import { nextTick, ref, computed } from 'vue'

const props = defineProps<{
  virtualRef: any
  columns: ColumnConfig[]
  fieldPicker: InstanceType<typeof import('./FieldPicker.vue')['default']>
}>()

const emit = defineEmits<{
  'update:sortBy': []
}>()

const sortingConfigPaneRef = ref()
const [ sortingConfigPaneVisible, toggleSortingConfigPaneVisible ] =
  useToggle(false)

const sortingConfig = defineModel<SortingConfig[]>({ required: true })

const selectableColumns = computed(() =>
  props.columns.filter(
    col => !sortingConfig.value.some(conf => conf.refCol?.field === col.field)
  )
)

const onRemoveSortingConfig = (config: SortingConfig) => {
  sortingConfig.value = toggle(
    sortingConfig.value,
    config,
    conf => conf.refCol.field
  )
  emit('update:sortBy')
}

const onClickOutside = () => {
  props.fieldPicker.toggleVisible(false)
}

const hasSorting = computed(() => sortingConfig.value.length > 0)

const handlePickSortingField = (col: ColumnConfig) => {
  if (hasSorting.value) {
    sortingConfig.value.push({ refCol: { ...col }, sort: 'asc' })
    emit('update:sortBy')
    return
  }
  sortingConfig.value = [ { refCol: { ...col }, sort: 'asc' } ]

  props.fieldPicker.toggleVisible(false)
  nextTick()
    .then(() => {
      toggleSortingConfigPaneVisible(true)
    })
    .then(() => {
      emit('update:sortBy')
    })
}

const onPickSortingField = async (e: MouseEvent) => {
  const picker = props.fieldPicker
  picker.setVirtualRef(e.target as HTMLElement | null)
  picker.setSelectableColumns(selectableColumns.value)
  picker.toggleVisible(true)
  const [ cancel, field ] = await tryit<never[], Promise<ColumnConfig>>(
    picker.pick
  )()
  if (cancel) {
    return
  }
  handlePickSortingField(field)
}
const [ ignoreClickOutside, toggleIgnoreClickOutside ] = useToggle(false)
const onSelectVisibleChange = (visible: boolean) => {
  toggleIgnoreClickOutside(visible)
}
const onClickPopoverOutside = () => {
  if (ignoreClickOutside.value) return
  toggleSortingConfigPaneVisible(false)
}
defineExpose({
  toggleVisible: toggleSortingConfigPaneVisible,
  handlePickSortingField
})
</script>
